﻿using Newtonsoft.Json;
using RabbitMQ.Client;
using RabbitMQ.Client.Events;
using Sorting.App.Models;
using System;
using System.Collections.Generic;
using System.Text;

namespace RabbitMQ
{
    public class RabbitMQHelper
    {
        ConnectionFactory connectionFactory;
        IConnection connection;
        IModel channel;
        string exchangeName;

        public RabbitMQHelper(IModel model, string changeName = "fanout_mq")
        {
            this.exchangeName = changeName;
            this.channel = model;
            channel.ConfirmSelect(); //开启服务端确认
            //这两个事件如果是using写法要写到创建交换器和队列并且进行绑定之前，否则不会触发
            channel.BasicNacks += (sender, e) =>
            {
                //生产者发送消息到broker（服务器）后失败被生产者的listener监听到，就走无应答方法
                Console.WriteLine(" --no ack-- " + e.ToString());
            };
            //有应答
            channel.BasicAcks += (sender, e) =>
            {
                Console.WriteLine(" --ack-- " + e.ToString());
            };


            //声明交换机
            channel.ExchangeDeclare(exchangeName, ExchangeType.Topic, durable: true, autoDelete: false, null);
        }


        /// <summary>
        /// 清除队列消息
        /// </summary>
        /// <param name="queName"></param>
        public void ClearAllMsg(string queName)
        {
 
            //声明一个队列
            channel.QueueDeclare(queName, true, false, false, null);
            //绑定队列，交换机，路由键
            channel.QueueBind(queName, exchangeName, queName);

            var basicProperties = channel.CreateBasicProperties();
            //1：非持久化 2：可持久化
            basicProperties.DeliveryMode = 2;

            channel.QueuePurge(queName);
        }

        /// <summary>
        /// 发送消息
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="queName"></param>
        /// <param name="msg"></param>
        public void SendMsg<T>(string queName, RabbitSend<dynamic> msg)
        {

            //声明一个队列
            channel.QueueDeclare(queName, true, false, false, null);
            //绑定队列，交换机，路由键
            channel.QueueBind(queName, exchangeName, queName);

            var basicProperties = channel.CreateBasicProperties();
            //1：非持久化 2：可持久化
            basicProperties.DeliveryMode = 2;
            var msgContent = JsonConvert.SerializeObject(msg);
            var payload = Encoding.UTF8.GetBytes(msgContent);
            var address = new PublicationAddress(ExchangeType.Direct, exchangeName, queName);

            channel.BasicPublish(address, basicProperties, payload);

            channel.WaitForConfirms();

        }

        /// <summary>
        /// 消费消息
        /// </summary>
        /// <param name="queName"></param>
        /// <param name="received"></param>
        public void Receive(string queName,  bool autoAsk, Func<string,ulong,IModel,bool> received)
        {
            try
            {

                //声明一个队列
                channel.QueueDeclare(queName, true, false, false, null);
                //绑定队列，交换机，路由键
                channel.QueueBind(queName, exchangeName, queName);

                var basicProperties = channel.CreateBasicProperties();
                //1：非持久化 2：可持久化
                basicProperties.DeliveryMode = 2;
                //事件基本消费者
                EventingBasicConsumer consumer = new EventingBasicConsumer(channel);

                //声明为手动确认，每次只消费1条消息。
                channel.BasicQos(0, 1, false);
                //接收到消息事件
                consumer.Received += (ch, ea) =>
                {
                    string message = Encoding.UTF8.GetString(ea.Body.Span);
                    var res = received(message,ea.DeliveryTag,channel);
                    //if (res)
                    //{
                    //    //确认该消息已被消费
                    //    channel.BasicAck(ea.DeliveryTag, false);
                    //}
                    //else
                    //{          //确认该消息已被消费
                    //    channel.BasicAck(ea.DeliveryTag, false);
                    //}

                };

                //启动消费者 设置为手动应答消息
                channel.BasicConsume(queName, autoAsk, consumer);
            }
            catch (Exception ex)
            {

                throw;
            }
        }


        /// <summary>
        /// 消费全部消息
        /// </summary>
        /// <param name="queName"></param>
        /// <param name="received"></param>
        public void ReceiveAll(string queName, Action<string> received)
        {


            //声明一个队列
            channel.QueueDeclare(queName, true, false, false, null);
            //绑定队列，交换机，路由键
            channel.QueueBind(queName, exchangeName, queName);
            var basicProperties = channel.CreateBasicProperties();
            //1：非持久化 2：可持久化
            basicProperties.DeliveryMode = 2;
            //事件基本消费者
            EventingBasicConsumer consumer = new EventingBasicConsumer(channel);
            //接收到消息事件
            consumer.Received += (ch, ea) =>
            {
                string message = Encoding.UTF8.GetString(ea.Body.Span);
                received(message);
                //确认该消息已被消费
                channel.BasicAck(ea.DeliveryTag, false);
            };

            //启动消费者 设置为手动应答消息
            channel.BasicConsume(queName, true, consumer);

        }



    }
}
